﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.Diagnostics;

namespace InfFront.InfoSources.Base.Design
{
    public partial class InfoSourceDesignerControl : BaseDesignerControl
    {
        public InfoSourceDesignerControl()
        {
            InitializeComponent();

            InitComponentCreationMenuStrip(mnuStripInfoSourceClasses, typeof(InfoSource));
        }

        private InfoSource Source
        {
            get { return (InfoSource) Component; }
        }

        protected override void Rebuild()
        {
            base.Rebuild();
            tvSources.BeginUpdate();
            RootSourceNode.Tag = Source;
            RootSourceNode.Nodes.Clear();
            if (Source != null)
            {
                RecursiveFillTree(RootSourceNode, Source.NestedSources);
            }
            tvSources.ExpandAll();
            tvSources.SelectedNode = RootSourceNode;
            tvSources.EndUpdate();
            tvSources.Select();
        }

        private TreeNode RootSourceNode
        {
            get { return tvSources.Nodes["-rootSourceNode"]; }
        }

        private void ResetItem(TreeNode tvi, InfoSource infs)
        {
            tvi.Tag = infs;
            tvi.Text = infs.Site.Name;
        }

        private TreeNode FindNodeFor(TreeNode parent, InfoSource source)
        {
            foreach (TreeNode node in parent.Nodes)
            {
                if (node.Tag == source)
                    return node;
                var childNode = FindNodeFor(node, source);
                if (childNode != null)
                    return childNode;
            }
            return null;
        }

        private TreeNode FindNodeFor(InfoSource source)
        {
            if (source != null)
            {
                var root = RootSourceNode;
                if (root.Tag == source)
                    return root;
                return FindNodeFor(root, source);
            }
            return null;
        }

        private void RecursiveFillTree(TreeNode parent, InfoSourceList sources)
        {
            //var actualComponents = Designer.Component.Site.Container.Components;
            foreach (var infs in sources)
            {
                //bool isDerived = false;
                //foreach (var obj in actualComponents)
                //{
                //    if (obj == infs)
                //    {
                //        isDerived = true;
                //        break;
                //    }
                //}
                //if (isDerived)
                //    continue;
                var tvi = new TreeNode();
                ResetItem(tvi, infs);
                parent.Nodes.Add(tvi);
                RecursiveFillTree(tvi, infs.NestedSources);
            }
        }

        protected override void OnAComponentChanged(object sender, ComponentChangedEventArgs e)
        {
 	        base.OnAComponentChanged(sender, e);

            if (e.Component != Component)
            {
                var node = FindNodeFor(e.Component as InfoSource);
                if (node != null)
                    ResetItem(node, (InfoSource)e.Component);
            }
        }

        protected override void OnAComponentRename(object sender, ComponentRenameEventArgs e)
        {
            if (e.Component != Component)
                base.OnAComponentRename(sender, e);
        }

        protected override void OnComponentRemoved(object sender, ComponentEventArgs e)
        {
            var asInfoSource = e.Component as InfoSource;
            if (asInfoSource != null)
            {
                var owner = asInfoSource.Owner;
                if (owner != null)
                    owner.NestedSources.Remove(asInfoSource);
                var node = FindNodeFor(asInfoSource);
                if (node != null)
                    node.Remove();
            }
        }

        protected override void OnComponentAdded(object sender, ComponentEventArgs e)
        {
            var asInfoSource = e.Component as InfoSource;
            if (asInfoSource != null)
            {
                var parentNode = tvSources.SelectedNode;
                if (parentNode == null)
                    parentNode = RootSourceNode;
                ((InfoSource) parentNode.Tag).NestedSources.Add(asInfoSource);
                var tvi = new TreeNode();
                ResetItem(tvi, asInfoSource);
                parentNode.Nodes.Add(tvi);
                tvSources.SelectedNode = tvi;
                tvSources.Select();
            }
        }

        private void lnkRemove_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            var tvi = tvSources.SelectedNode;
            if (tvi != null)
                DesignerHost.DestroyComponent((IComponent)tvi.Tag);
        }

        private void lnkAdd_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            mnuStripInfoSourceClasses.Show(lnkAdd, 1, lnkAdd.Height);
        }

        private void tvSources_AfterSelect(object sender, TreeViewEventArgs e)
        {
            var node = tvSources.SelectedNode;
            if (node == null || node == RootSourceNode)
            {
                SelectComponent(Component);
                if (node != null)
                    contentsDesignerControl.Designer = Designer;
                lnkRemove.Enabled = false;
                btnItemUp.Enabled = false;
                btnItemDown.Enabled = false;
                btnItemLeft.Enabled = false;
                btnItemRight.Enabled = false;
            }
            else
            {
                var source = (InfoSource)node.Tag;
                SelectComponent(source);
                contentsDesignerControl.Designer = DesignerHost.GetDesigner(source);
                lnkRemove.Enabled = true;
                btnItemUp.Enabled = (node.PrevNode != null);
                btnItemDown.Enabled = (node.NextNode != null);
                btnItemLeft.Enabled = (node.Parent != RootSourceNode);
                btnItemRight.Enabled = btnItemUp.Enabled;
            }
        }

        public void RecalcOrders(InfoSourceList list)
        {
            int i = 0;
            foreach (var itm in list)
            {
                var oldOrder = itm.Order;
                if (oldOrder != i)
                {
                    var props = TypeDescriptor.GetProperties(itm);
                    var prop = props["Order"];
                    ChangeService.OnComponentChanging(itm, prop);
                    itm.Order = i;
                    ChangeService.OnComponentChanged(itm, prop, oldOrder, i);
                }
                ++i;
            }
        }

        private void btnItemUp_Click(object sender, EventArgs e)
        {
            var node = tvSources.SelectedNode;
            Debug.Assert(node != null);
            var nodeParent = node.Parent;
            var nodeIndex = node.Index;
            nodeParent.Nodes.Remove(node);
            nodeParent.Nodes.Insert(nodeIndex - 1, node);

            var infoSource = (InfoSource)node.Tag;
            var parentSource = (InfoSource)nodeParent.Tag;
            nodeIndex = parentSource.NestedSources.IndexOf(infoSource);
            parentSource.NestedSources.Move(nodeIndex, nodeIndex - 1);

            RecalcOrders(parentSource.NestedSources);
            tvSources.SelectedNode = node;
            tvSources.Select();
        }

        private void btnItemDown_Click(object sender, EventArgs e)
        {
            var node = tvSources.SelectedNode;
            Debug.Assert(node != null);
            var nodeParent = node.Parent;
            var nodeIndex = node.Index;
            nodeParent.Nodes.Remove(node);
            nodeParent.Nodes.Insert(nodeIndex + 1, node);

            var infoSource = (InfoSource)node.Tag;
            var parentSource = (InfoSource)nodeParent.Tag;
            nodeIndex = parentSource.NestedSources.IndexOf(infoSource);
            parentSource.NestedSources.Move(nodeIndex, nodeIndex + 1);

            RecalcOrders(parentSource.NestedSources);
            tvSources.SelectedNode = node;
            tvSources.Select();
        }

        private void btnItemLeft_Click(object sender, EventArgs e)
        {
            var node = tvSources.SelectedNode;
            Debug.Assert(node != null);
            var infoSource = (InfoSource)node.Tag;
            var nodeParent = node.Parent;
            var nodeParentIndex = nodeParent.Index;
            var parentSource = (InfoSource)nodeParent.Tag;
            
            nodeParent.Nodes.Remove(node);
            parentSource.NestedSources.Remove(infoSource);
            RecalcOrders(parentSource.NestedSources);

            nodeParent = nodeParent.Parent;
            nodeParent.Nodes.Insert(nodeParentIndex + 1, node);
            nodeParentIndex = parentSource.Owner.NestedSources.IndexOf(parentSource);
            parentSource.Owner.NestedSources.Insert(nodeParentIndex + 1, infoSource);
            RecalcOrders(parentSource.Owner.NestedSources);
            tvSources.SelectedNode = node;
            tvSources.Select();
        }

        private void btnItemRight_Click(object sender, EventArgs e)
        {
            var node = tvSources.SelectedNode;
            Debug.Assert(node != null);
            var prevNode = node.PrevNode;
            Debug.Assert(prevNode != null);
            var infoSource = (InfoSource)node.Tag;
            var nodeParent = node.Parent;
            var parentSource = (InfoSource)nodeParent.Tag;

            nodeParent.Nodes.Remove(node);
            parentSource.NestedSources.Remove(infoSource);
            RecalcOrders(parentSource.NestedSources);

            nodeParent = prevNode;
            parentSource = (InfoSource)nodeParent.Tag;
            nodeParent.Nodes.Add(node);
            parentSource.NestedSources.Add(infoSource);
            RecalcOrders(parentSource.NestedSources);
            tvSources.SelectedNode = node;
            tvSources.Select();
        }
    }
}
